package org.huatek.anders.aspect;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.huatek.anders.exception.ApiException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * @author anders
 * @date 2018-12-21 13:19
 **/
@Aspect
@Component
@Slf4j
public class RequestLogAspect {
    @Value("${common.visitor.url}")
    private String[] visitorUrl;
    @Value("${common.log.show}")
    private boolean logShow;

    @Pointcut("@annotation(RequestLog)")
    public void logCut() {
    }
    @Around("logCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable{
        //获取request
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)requestAttributes;
        HttpServletRequest request = null;
        if (servletRequestAttributes != null) {
            request = servletRequestAttributes.getRequest();
        }else{
            throw new ApiException("logCut 日志 request 为空");
        }
        long beginTime = System.currentTimeMillis();
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        RequestLog requestLog = method.getAnnotation(RequestLog.class);

        if (requestLog.isBefore()) {
            if (logShow){
                log.debug("==========request before log before begin...========");
                printRequestLog(point, signature, requestLog, 0, request);
                log.debug("==========request before log before end...========");
            }
        }
        Object result = point.proceed();
        long time = System.currentTimeMillis() - beginTime;
        if (requestLog.isAfter()) {
            if (logShow){
                log.debug("==========request after log before begin...========");
                printRequestLog(point, signature, requestLog, time, request);
                log.debug("==========request after log before end...========");
            }
        }

        return result;
    }
    private void printRequestLog(ProceedingJoinPoint joinPoint, MethodSignature signature, RequestLog requestLog,
                                 long time, HttpServletRequest request) throws JsonProcessingException {
        String ip = request.getRemoteAddr();
        String requestUrl = request.getRequestURI();
        StringBuilder sb = new StringBuilder();
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();

        sb.append("接口请求begin........")
                .append("\n")
                .append("IP：").append(ip)
                .append("\n")
                .append("URL：").append(requestUrl)
                .append("\n")
                .append("执行方法：").append(className).append(".").append(methodName).append("()")
                .append("\n")
                .append("描述：").append(requestLog.value());

        Object[] args = joinPoint.getArgs();
        ObjectMapper mapper = new ObjectMapper();
        Map<Object, Object> argMap = new HashMap<>(16);
        sb.append("请求参数：").append("\n");
        Arrays.stream(args)
                .filter(arg->!(arg instanceof HttpServletRequest || arg instanceof HttpServletResponse))
                .forEach(arg->{
                    try {
                        argMap.put(arg, mapper.writerWithDefaultPrettyPrinter().writeValueAsString(arg));
                    } catch (JsonProcessingException e) {
                        e.printStackTrace();
                    }
                });
        sb.append(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(argMap))
        .append("执行时长：").append(time)
                .append("\n");
///        sb.append(System.getProperty("line.separator"));
        log.debug(sb.toString());
        log.debug("接口请求end........");
    }

}
